<template>
    <div>
        <a-cascader
            placeholder="请选择"
            v-model:value="value"
            v-bind="bindValues"
            :options="options"
            :fieldNames="{ label: labelField, value: valueField, children: childrenField }"
            @change="handleCascaderChange"
        >
            <slot name="displayRender" />
        </a-cascader>
    </div>
</template>

<script lang="ts">
// 传入目标值code，即可回显出路径
import { deepClone } from '@/utils/util';
import { defineComponent, toRefs, watch, reactive } from 'vue';
export default defineComponent({
    props: {
        labelField: {
            type: String,
            default: 'label'
        },
        valueField: {
            type: String,
            default: 'value'
        },
        childrenField: {
            type: String,
            default: 'children'
        },
        options: {
            type: Array,
            default: () => []
        }
    },
    emits: ['change'],
    // defaultValue
    setup(props, { emit, attrs }) {
        const state = reactive<any>({
            value: [],
            bindValues: {}
        });
        // 获取整条树
        const treeFilter = (tree: any[], func: Function) => {
            // 使用map复制一下节点，避免修改到原树
            return tree
                .map((node) => ({ ...node }))
                .filter((node: any) => {
                    node[props.childrenField] = node[props.childrenField] && treeFilter(node[props.childrenField], func);
                    return func(node) || (node[props.childrenField] && node[props.childrenField].length);
                });
        };
        // 获取路径id
        const getMenuId = (obj: any, path: any = []) => {
            path.push(obj[props.valueField]);
            if (obj[props.childrenField] && obj[props.childrenField].length) {
                getMenuId(obj[props.childrenField][0], path);
            }
            return path;
        };
        // 获取节点详细信息
        const getItem = (val, defaultOptions) => {
            let options = defaultOptions;
            let target: any = {};
            while (val.length) {
                const id = val.shift();
                target = options.find((item) => item[props.valueField] === id);
                if (target) {
                    options = target[props.childrenField];
                }
            }
            return target;
        };
        const handleClear = () => {
            state.value = [];
        };

        const handleCascaderChange = (val) => {
            // 节点信息
            const item = getItem(deepClone(val), props.options);
            emit('change', {
                nodeInfo: item,
                nodeArr: val
            });
        };
        const filter = (inputValue, path) => {
            return path.some((option) => option[props.labelField].toLowerCase().indexOf(inputValue.toLowerCase()) > -1);
        };
        const init = () => {
            // 默认属性
            const defaultBindValues = {};
            if (attrs['show-search']) {
                if (typeof attrs['show-search'] === 'boolean') {
                    defaultBindValues['show-search'] = {
                        filter
                    };
                } else {
                    defaultBindValues['show-search'] = Object.assign({ filter }, attrs['show-search']);
                }
            }
            // 针对default-value
            if (props.options && props.options.length && attrs['default-value']) {
                if (attrs['default-value']) {
                    const target = treeFilter(props.options, (node) => node[props.valueField] === attrs['default-value']);
                    state.value = getMenuId(target[0]);
                    const item = getItem(deepClone(state.value), props.options);
                    // 针对默认值要回调，赋值给默认的对象比如parentInfo
                    emit('change', {
                        nodeInfo: item,
                        nodeArr: state.value
                    });
                }
            } else {
                state.value = [];
            }
            state.bindValues = {
                ...attrs,
                ...defaultBindValues,
                ['default-value']: state.value
            };
        };
        // 会出现一个问题，如果options和value同时更新，会取不到value的值
        watch(
            () => props.options,
            (n) => {
                if (n && n.length) {
                    init();
                }
            },
            {
                deep: true,
                immediate: true
            }
        );
        return {
            ...toRefs(state),
            handleCascaderChange,
            handleClear
        };
    }
});
</script>

<style lang="less">
.ant-cascader-menu {
    min-width: 250px !important;
}
</style>
<style scoped lang="less">
::v-deep(.ant-cascader-picker) {
    min-width: 250px;
}
</style>
